/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin		 	*/
/*	Project:	GlbLib-1.0.0			*/
/*	Author:		gong_libin			*/
/*	Date:		2016_06_01			*/
/*	File:		GlbMulti.cpp			*/
/********************************************************/

#include "GlbMulti.h"

namespace GlbNet
{

CGlbMulti::CGlbMulti()
{
	memset(&m_stMulti, '\0', sizeof(struct sockaddr_in));
}

CGlbMulti::~CGlbMulti()
{
}

void* CGlbMulti::GlbMultiGetMulti()
{
	return (void*)&m_stMulti;
}

void CGlbMulti::GlbMultiSetMulti(void* pAddr)
{
	memcpy(&m_stMulti, pAddr, sizeof(struct sockaddr_in));

	return;
}

int CGlbMulti::GlbNetInitSend(char* pszUrl)
{
	char* pszPort = NULL;
	int iReturn = GLB_SUCCESS;

	if (NULL != (pszPort = CGlbNet::GlbNetUrl(pszUrl))) {
		iReturn = GlbNetInitSend(pszUrl, pszPort);
	}
	else {
		iReturn = GLB_FAILURE;
	}

	return iReturn;
}

int CGlbMulti::GlbNetInitRecv(char* pszUrl)
{
	char* pszPort = NULL;
	int iReturn = GLB_SUCCESS;

	if (NULL != (pszPort = CGlbNet::GlbNetUrl(pszUrl))) {
		iReturn = GlbNetInitRecv(pszUrl, pszPort);
	}
	else {
		iReturn = GLB_FAILURE;
	}

	return iReturn;
}

int CGlbMulti::GlbNetInitSend(struct sockaddr_in* pstAddr)
{
	if (NULL != pstAddr) {
		memcpy(&m_stMulti, pstAddr, sizeof(struct sockaddr_in));
	}

	if (GLB_SUCCESS != CGlbNet::GlbNetOpen(GLB_AF_INET, SOCK_DGRAM)) {
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

int CGlbMulti::GlbNetInitRecv(struct sockaddr_in* pstAddr)
{
	struct ip_mreq stMreq;

	if (NULL != pstAddr) {
		memcpy(&m_stMulti, pstAddr, sizeof(struct sockaddr_in));
	}

	memset(&stMreq, '\0', sizeof(struct ip_mreq));
	stMreq.imr_interface.s_addr = htonl(INADDR_ANY);
	stMreq.imr_multiaddr.s_addr = m_stMulti.sin_addr.s_addr;

	if (GLB_SUCCESS != CGlbNet::GlbNetOpen(GLB_AF_INET, SOCK_DGRAM)) {
		return GLB_FAILURE;
	}

	if (GLB_SUCCESS != CGlbNet::GlbNetSetReuseAddr()) {
		return GLB_FAILURE;
	}

	m_stMulti.sin_addr.s_addr = htonl(INADDR_ANY);
	if (GLB_SUCCESS != GlbNetBind(&m_stMulti)) {
		GLB_ERROR("%s\n", strerror(errno));
		CGlbNet::GlbNetClose();
		return GLB_FAILURE;
	}

	if (setsockopt(CGlbNet::m_iSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &stMreq, sizeof(struct ip_mreq)) < 0) {
		GLB_ERROR("%s\n", strerror(errno));
		CGlbNet::GlbNetClose();
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

int CGlbMulti::GlbNetInitSend(char* pszAddress, char* pszPort)
{
	m_stMulti.sin_family = AF_INET;
	m_stMulti.sin_port = htons(atoi(pszPort));
	m_stMulti.sin_addr.s_addr = inet_addr(pszAddress);

	if (GLB_SUCCESS != CGlbNet::GlbNetOpen(GLB_AF_INET, SOCK_DGRAM)) {
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

int CGlbMulti::GlbNetInitRecv(char* pszAddress, char* pszPort)
{
	struct ip_mreq stMreq;

	m_stMulti.sin_family = AF_INET;
	m_stMulti.sin_port = htons(atoi(pszPort));
	m_stMulti.sin_addr.s_addr = htonl(INADDR_ANY);

	if (GLB_SUCCESS != CGlbNet::GlbNetOpen(GLB_AF_INET, SOCK_DGRAM)) {
		return GLB_FAILURE;
	}

	if (GLB_SUCCESS != CGlbNet::GlbNetSetReuseAddr()) {
		return GLB_FAILURE;
	}

	if (GLB_SUCCESS != GlbNetBind(&m_stMulti)) {
		GLB_ERROR("%s\n", strerror(errno));
		CGlbNet::GlbNetClose();
		return GLB_FAILURE;
	}

	memset(&stMreq, '\0', sizeof(struct ip_mreq));
	stMreq.imr_interface.s_addr = htonl(INADDR_ANY);
	stMreq.imr_multiaddr.s_addr = inet_addr(pszAddress);

	if (setsockopt(CGlbNet::m_iSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &stMreq, sizeof(struct ip_mreq)) < 0) {
		GLB_ERROR("%s\n", strerror(errno));
		CGlbNet::GlbNetClose();
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

int CGlbMulti::GlbNetSendAll(UCHAR* puszPacket, int iLength)
{
	int iCount = 0;
	int iTotal = 0;

	while (iTotal < iLength) {
		if ((iCount = GlbNetSend(puszPacket + iTotal, iLength - iTotal)) > 0) {
			iTotal += iCount;
		}
		else {
			GLB_ERROR("%s\n", strerror(errno));
			break;
		}
	}

	return iTotal;
}

int CGlbMulti::GlbNetRecvAll(UCHAR* puszPacket, int iLength)
{
	int iCount = 0;
	int iTotal = 0;

	while (iTotal < iLength) {
		if ((iCount = GlbNetRecv(puszPacket + iTotal, iLength - iTotal)) > 0) {
			iTotal += iCount;
		}
		else {
			GLB_ERROR("%s\n", strerror(errno));
			break;
		}
	}

	return iTotal;
}

} /* GlbNet */
